package com.netty.http;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author 咕唧
 * @Date 2022/7/7 22:31
 * @Version 1.0
 */
public class MyHttpHandler extends SimpleChannelInboundHandler<HttpObject> {

    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
        System.out.println("MyHttpHandler的channelRead0方法执行了");
        //当有请求过来的时候，会到达这个地址
        //比如我们模拟一个简单的springmvc的感觉, 一个get请求传递几个参数过来,然后到达我们的controller,返回结果
        if (msg instanceof HttpRequest) {
            //获取到请求的地址,这个地址包括了get中传递的参数 ?以及之后的东西
            String uri = ((HttpRequest) msg).uri();
            //path是我们的请求地址,暂时和用户请求的是一样,但是如果有?就不一样了,我们需要裁剪,将地址和参数分开
            String path = uri;
            //保存参数的集合
            Map paramMap = new HashMap();
            //取出路径中的参数
            if (uri.contains("?")) {
                path = path.substring(0,uri.indexOf("?") );
                //取出参数
                String queryString = uri.substring(uri.indexOf("?") + 1);
                //将参数以&分割得到 多个key=value的字符串
                String[] allParam = queryString.split("&");
                //遍历集合，拿到参数和属性
                for (String s : allParam) {
                    String[] split = s.split("=");
                    //保存参数
                    paramMap.put(split[0], split[1]);
                }
            }
            System.out.println(paramMap);
            //看看这个地址对应什么方法
            Method method = RequestUtil.url2Method.get(path);
            if (method != null) {
                //查看方法对应的类
                Object controller = RequestUtil.url2Object.get(path);
                //获取方法对应的参数名称，我们首先得知道我们这个方法的参数的顺序,然后把传递过来的参数按照顺序拍好,然后传递过来,还不能多传,也不能少传,个数必须匹配
                Parameter[] parameters = method.getParameters();
                //创建一个和方法长度一样的数组保存用户传递的的参数
                Object[] params = new Object[parameters.length];
                //需要知道它需要的每一个参数的名字
                for (int i = 0; i < parameters.length; i++) {
                    //得到每个位置的参数
                    Parameter parameter = parameters[i];
                    //得到每个参数的名字,这个参数的名字必须通过配置获取，否则，默认获取到的参数名称为args0和args1
                    String name = parameter.getName();
                    //将参数保存到数组当中
                    params[i] = paramMap.get(name);
                }
                System.err.println(params);
                Object result = method.invoke(controller, params);
                System.err.println("返回结果是:" + result);
                //吧返回的结果转换成json
                String json = objectMapper.writeValueAsString(result);
                ByteBuf buffer = Unpooled.copiedBuffer(json.getBytes(StandardCharsets.UTF_8));
                //创建一个响应对象
                DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buffer);
                httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json;charset=utf-8");
                ctx.writeAndFlush(httpResponse);
                ctx.close();
            } else {
                DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND);
                httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json;charset=utf-8");
                ctx.close();
            }
        }
    }

}
